using System;
using System.Collections.Generic;
using System.Text;
using AgilePlannerDT.Data;
using System.ComponentModel;
using AgilePlannerDT.Display.Events;

namespace AgilePlannerDT.Data.Impl
{
    public class IndexCardDataObject : IndexCard
    {
        public int SyncID { get; set; }
        #region Constants

        public static readonly string ID_PROPERTY = "ID";
        public static readonly string NAME_PROPERTY = "Name";
        public static readonly string ACTUAL_EFFORT_PROPERTY = "ActualEffort";
        public static readonly string BEST_CASE_ESTIMATE_PROPERTY = "BestCaseEstimate";
        public static readonly string DESCRIPTION_PROPERTY = "Description";
        public static readonly string HEIGHT_PROPERTY = "Height";
        public static readonly string LOCATION_X_PROPERTY = "LocationX";
        public static readonly string LOCATION_Y_PROPERTY = "LocationY";
        public static readonly string MOST_LIKELY_ESTIMATE_PROPERTY = "MostlikelyEstimate";
        public static readonly string PARENT_PROPERTY = "Parent";
        public static readonly string STATUS_PROPERTY = "Status";
        public static readonly string WIDTH_PROPERTY = "Width";
        public static readonly string WORST_CASE_ESTIMATE_PROPERTY = "WorstCaseEstimate";

        //artificial properties for size and position (they change too frequently to
        //fire notifies on every update)
        public static readonly string POSITION_PROPERTY = "Position";
        public static readonly string SIZE_PROPERTY = "Size";

        #endregion

        #region Attributes

        protected long id, parent;

        protected double width, height, locationX, locationY, rotationAngle;

        protected string name, description, status;

        protected IndexCardWithChild parentCard;

        protected float actualEffort, bestCaseEstimate, mostLikelyEstimate, worstCaseEstimate;

        #endregion

        #region Events

        public event PropertyChangedEventHandler PropertyChanged;

        #endregion

        #region AbstractRoot Members

        public String Name
        {
            get { return this.name; }
            set
            {
                if (this.name == value)
                {
                    return;
                }
                object before = Clone();
                this.name = value;
                object after = Clone();
                Notify(NAME_PROPERTY, before, after);
                //Notify(NAME_PROPERTY);
            }
        }

        public long ID
        {
            get { return this.id; }
            set
            {
                if (this.id == value)
                {
                    return;
                }
                object before = Clone();
                this.id = value;
                object after = Clone();
                Notify(ID_PROPERTY, before, after);
                //Notify(ID_PROPERTY);
            }
        }

        #endregion

        #region IndexCard Members

        public Project getProject(){
           return ParentCard.Project;
        }

        public IndexCardWithChild ParentCard{
            get;
            set;
        }

        public float ActualEffort
        {
            get { return this.actualEffort; }
            set
            {
                if (this.actualEffort == value)
                {
                    return;
                }
                object before = Clone();
                this.actualEffort = value;
                object after = Clone();
                Notify(ACTUAL_EFFORT_PROPERTY, before, after);
                //Notify(ACTUAL_EFFORT_PROPERTY);
            }
        }

        public float BestCaseEstimate
        {
            get { return this.bestCaseEstimate; }
            set
            {
                if (this.bestCaseEstimate == value)
                {
                    return;
                }
                object before = Clone();
                this.bestCaseEstimate = value;
                object after = Clone();
                Notify(BEST_CASE_ESTIMATE_PROPERTY, before, after);
                //Notify(BEST_CASE_ESTIMATE_PROPERTY);
            }
        }

        public string Description
        {
            get { return this.description; }
            set
            {
                if (this.description == value)
                {
                    return;
                }
                object before = Clone();
                this.description = value;
                object after = Clone();
                Notify(DESCRIPTION_PROPERTY, before, after);
                //Notify(DESCRIPTION_PROPERTY);
            }
        }

        public double Height
        {
            get { return this.height; }
            set
            {
                if (this.height == value)
                {
                    return;
                }
                this.height = value;
                //do not notify! value changes too often
            }
        }

        public double LocationX
        {
            get { return this.locationX; }
            set
            {
                if (this.locationX == value)
                {
                    return;
                }
                this.locationX = value;
                //do not notify! value changes too often
            }
        }

        public double LocationY
        {
            get { return this.locationY; }
            set
            {
                if (this.locationY == value)
                {
                    return;
                }
                this.locationY = value;
                //do not notify! value changes too often
            }
        }

        public float MostlikelyEstimate
        {
            get { return this.mostLikelyEstimate; }
            set
            {
                if (this.mostLikelyEstimate == value)
                {
                    return;
                }
                object before = Clone();
                this.mostLikelyEstimate = value;
                object after = Clone();
                Notify(MOST_LIKELY_ESTIMATE_PROPERTY, before, after);
                //Notify(MOST_LIKELY_ESTIMATE_PROPERTY);
            }
        }

        public long Parent
        {
            get { return this.parent; }
            set
            {
                if (this.parent == value)
                {
                    return;
                }
                this.parent = value;
                //do not notify. causes conflicting updates
                //on MoveToNewParent
            }
        }

        public float RemainingEffort
        {
            get { return mostLikelyEstimate - actualEffort; }
        }

        public double RotationAngle
        {
            get { return this.rotationAngle; }
            set
            {
                if (this.rotationAngle == value)
                {
                    return;
                }
                this.rotationAngle = value;
                //do not notify! value changes too often
            }
        }

        public String Status
        {
            get { return this.status; }
            set
            {
                if (this.status == value)
                {
                    return;
                }
                object before = Clone();
                this.status = value;
                object after = Clone();
                Notify(STATUS_PROPERTY, before, after);
                //Notify(STATUS_PROPERTY);
            }
        }

        public double Width
        {
            get { return this.width; }
            set
            {
                if (this.width == value)
                {
                    return;
                }
                this.width = value;
                //do not notify! value changes too often
            }
        }

        public float WorstCaseEstimate
        {
            get { return this.worstCaseEstimate; }
            set
            {
                if (this.worstCaseEstimate == value)
                {
                    return;
                }
                object before = Clone();
                this.worstCaseEstimate = value;
                object after = Clone();
                Notify(WORST_CASE_ESTIMATE_PROPERTY, before, after);
                //Notify(WORST_CASE_ESTIMATE_PROPERTY);
            }
        }

        public bool IsCompleted
        {
            get { return false; }
        }

        public bool IsStarted
        {
            get { return false; }
        }

        #endregion

        #region INotifyPropertyChanged

        protected void Notify(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        public void Notify(string propertyName, object before, object after)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new IndexCardPropertyChangedEventArgs(propertyName, before, after));
            }
        }

        #endregion

        #region Object Members

        public override bool Equals(Object o)
        {
            if (o is IndexCardDataObject)
            {
                IndexCardDataObject card = (IndexCardDataObject)o;
                return (this.id == card.ID);
            }
            else
                return false;
        }


        public override int GetHashCode()
        {
            return (int)this.id;
        }

        #endregion

        #region IComparable<IndexCard> Members

        public int CompareTo(IndexCard other)
        {
            return id.CompareTo(other.ID);
        }

        #endregion

        #region ICloneable Members

        public virtual object Clone()
        {
            throw new NotImplementedException();
        }

        #endregion
    }
}